﻿using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace FtpWorkSession2
{
    public class FTPWorks
    {
        // Fields
        public delegate void StatusDelegate(string s, bool b);

        public event StatusDelegate ShowStatus;
        private IntPtr lFtpHandle;
        private IntPtr lInternetHandle;

        // Methods
        public void CloseConnection()
        {
            InternetCloseHandle(this.lFtpHandle);
            InternetCloseHandle(this.lInternetHandle);
        }

        [DllImport("wininet.dll")]
        public static extern IntPtr FtpFindFirstFile(IntPtr ulSession, string strPath, [In, Out] FileData dirData, ulong ulFlags, ulong ulContext);
        [DllImport("wininet.dll")]
        public static extern bool FtpGetFile(IntPtr ulSession, string strRemoteFile, string strLocalFile, bool bolFailIfExist, ulong ulFlags, ulong ulInetFals, ulong ulContext);
        //[DllImport("wininet.dll")]
        //public static extern bool FtpSetCurrentDirectory(IntPtr ulSession, string strPath);
        
        public bool GetFileFromFtp(string remotefile, string localfile, bool rewrite)
        {
            FileInfo file = new FileInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase)+"/"+localfile);
            ShowStatus("Завантаження файлу " + file.Name + "...", false);
            if (!FtpGetFile(this.lFtpHandle, remotefile, localfile, rewrite, 2L, 0L, 0L))
            {
                ShowStatus("Помилка при завантаженні файлу " + file.Name, true);
                return false;
            }
            ShowStatus("OK " + file.Name, true);
            return true;
        }
        
        public bool GetFilesFromFTP(string remotefile, string localfile, bool rewrite)
        {
            FileInfo info2;
            bool exists;
            bool flag2;
            if (remotefile[remotefile.Length - 1] == '/')
            {
                ShowStatus("Current dir " + remotefile, false);
                FileData dirData = new FileData();
                IntPtr ulFindFirst = FtpFindFirstFile(this.lFtpHandle, remotefile + "", dirData, 0x80000000L, 0L);
                if (ulFindFirst.ToInt32() == 0)
                {
                    ShowStatus("Каталог пуст", false);
                    return false;
                }
                List<FileData> list = new List<FileData>();
                do
                {
                    FileData item = new FileData();
                    item.fileAttributes = dirData.fileAttributes;
                    item.fileName = dirData.fileName;
                    list.Add(item);
                }
                while (InternetFindNextFile(ulFindFirst, dirData));
                InternetCloseHandle(ulFindFirst);
                foreach (FileData data3 in list)
                {
                    ShowStatus(data3.fileName, false);
                    if (data3.fileAttributes == 0x10)
                    {
                        DirectoryInfo info = new DirectoryInfo(localfile + data3.fileName);
                        if (!info.Exists)
                        {
                            Directory.CreateDirectory(localfile + data3.fileName);
                        }
                        this.GetFilesFromFTP(remotefile + data3.fileName + "/", localfile + data3.fileName + @"\", rewrite);
                    }
                    else
                    {
                        info2 = new FileInfo(localfile + data3.fileName);
                        exists = info2.Exists;
                        flag2 = true;
                        if (!((!exists || rewrite) && exists))
                        {
                            ShowStatus("Идет получение файла " + data3.fileName + "...", false);
                            flag2 = FtpGetFile(this.lFtpHandle, remotefile + data3.fileName, localfile + data3.fileName, rewrite, 2L, 0L, 0L);
                        }
                        if (!flag2)
                        {
                            ShowStatus("Невозможно получить файл " + data3.fileName, false);
                        }
                        else
                        {
                            ShowStatus("Файл " + data3.fileName + " получен", false);
                        }
                    }
                }
            }
            else
            {
                
                string[] strArray;
                if (localfile[localfile.Length - 1] == '\\')
                {
                    strArray = remotefile.Split(new char[] { '/' });
                    info2 = new FileInfo(localfile + strArray[strArray.Length - 1]);
                    exists = info2.Exists;
                    flag2 = true;
                    if (!((!exists || rewrite) && exists))
                    {
                        ShowStatus("Идет получение файла " + strArray[strArray.Length - 1] + "...", false);
                        flag2 = FtpGetFile(this.lFtpHandle, remotefile, localfile + strArray[strArray.Length - 1], rewrite, 2L, 0L, 0L);
                    }
                    if (!flag2)
                    {
                        ShowStatus("Ошибка получения файла " + strArray[strArray.Length - 1] + ". Файл не найден на сервере или вы неправильно указали настройки", true);
                        return false;
                    }
                }
                else
                {
                    strArray = remotefile.Split(new char[] { '/' });
                    info2 = new FileInfo(localfile);
                    exists = info2.Exists;

                    flag2 = true;
                    if (!((!exists || rewrite) && exists))
                    {
                        ShowStatus("Идет получение файла " + strArray[strArray.Length - 1] + "...", false);
                        flag2 = FtpGetFile(this.lFtpHandle, remotefile, localfile, rewrite, 2L, 0L, 0L);
                    }
                    if (!flag2)
                    {
                        ShowStatus("Ошибка получения файла " + strArray[strArray.Length - 1] + ". Файл не найден на сервере или вы неправильно указали настройки", true);
                        return false;
                    }
                }
            }
            return true;
        }

        [DllImport("wininet.dll")]
        public static extern bool FtpPutFile(IntPtr hConnect, string lpszLocalFile, string lpszNewRemoteFile,
                                             ulong dwFlags, ulong dwContext);

        public bool FtpPutFile (string remotefile, string localfile, bool rewrite)
        {
            if (FtpPutFile(lFtpHandle, localfile, remotefile, 0L, 0L))
            {
                ShowStatus("Помилка при завантаженні файлу " , true);
                return false;
            }
            ShowStatus("OK ", true);
            return true;
        }

        [DllImport("wininet.dll")]
        public static extern bool InternetCloseHandle(IntPtr hInet);
        [DllImport("wininet.dll", CharSet = CharSet.Unicode)]
        private static extern IntPtr InternetConnect(IntPtr hInternet, string ServerName, ushort ServerPort, string sUserName, string sPassword, uint nService, uint nFlags, uint nContext);
        [DllImport("wininet.dll")]
        public static extern bool InternetFindNextFile(IntPtr ulFindFirst, [In, Out] FileData dirData);
        [DllImport("wininet.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr InternetOpen(string sAgent, uint nAccessType, string sProxy, string sProxyBypass, uint nFlags);
        
        public bool OpenConnection(string strFTPServerName, ushort intFTPPort, string strUsername, string strPassword)
        {
            uint nFlags = 0x00000000;
            uint nService = 1;
            this.lInternetHandle = InternetOpen("FTPOpen", 1, "", "", 0);
            ShowStatus("Попытка подключения к фтп серверу...", false);
            if (this.lInternetHandle.ToInt32() == 0)
            {
                ShowStatus("Невозможно начать сессию", true);
                return false;
            }
            this.lFtpHandle = InternetConnect(this.lInternetHandle, strFTPServerName, intFTPPort, strUsername, strPassword, nService, nFlags, 0);
            if (this.lFtpHandle.ToInt32() == 0)
            {
                ShowStatus("Невозможно подключится к ftp серверу", true);
                return false;
            }
            ShowStatus("Подключено.", false);
            return true;
        }

        // Nested Types
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public class FileData
        {
            public int fileAttributes = 0;
            public int creationTime_lowDateTime = 0;
            public int creationTime_highDateTime = 0;
            public int lastAccessTime_lowDateTime = 0;
            public int lastAccessTime_highDateTime = 0;
            public int lastWriteTime_lowDateTime = 0;
            public int lastWriteTime_highDateTime = 0;
            public int nFileSizeHigh = 0;
            public int nFileSizeLow = 0;
            public int dwReserved0 = 0;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x100)]
            public string fileName = "";
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
            public string alternateFileName = "";
        }
    }


}
